package com.gmail.dengtao.joe.group.packet.impl;

import java.nio.ByteBuffer;

import com.gmail.dengtao.joe.commons.util.ByteUtils;
import com.gmail.dengtao.joe.group.packet.ChannelPacket;

/**
 * The <code>ChannelPacketImpl</code> object is used to transfer a message through the 
 * channel interceptor stack and eventually out on a transport to be sent 
 * to another node. While the message is being processed by the different 
 * interceptors, the message data can be manipulated as each interceptor seems appropriate.
 * @author <a href="mailto:joe.dengtao@gmail.com">DengTao</a>
 * @version 1.0
 * @since 1.0
 */
public class ChannelPacketImpl implements ChannelPacket {
	
	/**
	 * Packet type define...
	 * @author <a href="mailto:joe.dengtao@gmail.com">DengTao</a>
	 * @version 1.0
	 * @since 1.0
	 */
	public interface Type {
		public static final int HELLO = 0;
		public static final int ACK = 1;
		public static final int PULSE = 3;
		public static final int DATA = 5;
	}
	
	// Packet Head
	private int len = 0;// total length
	private int type;	// packet type
	private int pn;	// packet number
	private int sn;	// serial number
	private int an;	// ack number
	private int mf;	// more packet flag
	
	// Packet Body
	private byte[] data;// data
	
	public ChannelPacketImpl(int type, int pn, int sn, int an, int mf,
			byte[] data) {
		this.type = type;
		this.pn = pn;
		this.sn = sn;
		this.an = an;
		this.mf = mf;
		this.data = data;
		this.len = ByteUtils.sizeOf(len, type, pn, sn, an, mf, data);
	}

	/**
	 * @return whether this packet has more packet
	 * @since 1.0
	 */
	public int getMorePacket() {
		return mf;
	}
	
	/**
	 * @return whether this packet has more packet
	 * @since 1.0
	 */
	public boolean isMorePacket() {
		if (mf == 1) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * @return this packet's ack number
	 * @since 1.0
	 */
	public int getAckNumber() {
		return an;
	}
	
	/**
	 * @return this packet's serial number
	 * @since 1.0
	 */
	public int getSerialNumber() {
		return sn;
	}
	
	/**
	 * @return this packet's packet number
	 * @since 1.0
	 */
	public int getPacketNumber() {
		return pn;
	}
	
	
	@Override
	public int getLength() {
		return len;
	}

	@Override
	public void setData(byte[] data) {
		this.data = data;
		this.len = ByteUtils.sizeOf(len, type, pn, sn, an, mf, this.data);
	}
	
	@Override
	public byte[] getData() {
		return data;
	}

	@Override
	public int getType() {
		return type;
	}
	
	@Override
	public Object clone() {
		return new ChannelPacketImpl(type, pn, sn, an, mf, data);
	}

	@Override
	public byte[] toBytes() {
		ByteBuffer buffer = ByteBuffer.allocate(len);
		buffer.putInt(len);
		buffer.putInt(type);
		buffer.putInt(pn);
		buffer.putInt(sn);
		buffer.putInt(an);
		buffer.putInt(mf);
		buffer.put(data);
		return buffer.array();
	}

}